package com.maixy.studyonlineapi.utils;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author HuangLinWei
 * @since 2019/4/12
 */
public class Coalesce {

    public static <T> T coalesce(Supplier<T>... ts) {
        return Arrays.stream(ts)
                .map(Supplier::get)
                .filter(Objects::nonNull)
                .findFirst()
                .orElse(null);
    }

    public interface AnotherSupplier<T> extends Supplier<T> {
    }

    public static <T> Optional<T> coalesce(AnotherSupplier<Optional<T>>... ts) {
        return Arrays.stream(ts)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst()
                .orElse(Optional.empty());
    }

    public static <T> Optional<T> coalesce(Optional<T>... ts) {
        return Arrays.stream(ts)
                .filter(Optional::isPresent)
                .findFirst()
                .orElse(Optional.empty());
    }

    @SafeVarargs
    public static <T> T coalesce(T... ts) {
        return Arrays.stream(ts)
                .filter(Objects::nonNull)
                .findFirst()
                .orElse(null);
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 用于批量equals，用t1 equals t2的每一个元素，如果全部都是false就返回true，否则就返回false
     *
     * @param t1
     * @param t2
     * @return boolean
     * @author HuangLinWei
     * @since 2019/10/10
     */
    public static <T> boolean notEquals(T t1, T... t2) {
        return Arrays.stream(t2)
                .filter(Objects::nonNull)
                .noneMatch(t1::equals);
    }

    /**
     * 批量equals，用t1 equals t2的每一个元素，只要有一个为true就返回true
     *
     * @param t1
     * @param t2
     * @return boolean
     * @author HuangLinWei
     * @since 2019/11/15
     */
    public static <T> boolean anyEquals(T t1, T... t2){
        return Arrays.stream(t2)
                .filter(Objects::nonNull)
                .anyMatch(t1::equals);
    }

}
